// SPDX-FileCopyrightText: Copyright 2025-2025 深圳市同心圆网络有限公司 
// SPDX-License-Identifier: GPL-3.0-only 

import { writable } from "svelte/store";
import {
    type Node as FlowNode,
    type Edge as FlowEdge,
    type XYPosition,
    type Connection,
    MarkerType,
} from "@xyflow/svelte";
import { drawStore } from "./store.svelte";
import { create_edge, create_node, EDGE_TYPE_BEZIER, remove_edge, remove_node, report_mouse_position, update_node_position, type BasicEdgeInfo, type DrawEdgeInfo, type EdgeKey, type ExDrawNodeInfo, type NodeStyleInfo } from "$lib/api/board/board_draw";
import { getNodeType } from "./nodes/types.svelte";
import { get_user_session } from "$lib/api/user";
import { request } from "$lib/utils/request";
import dayjs from "dayjs";

export interface CurDrawNodeInfo {
    id: string;
    x1: number;
    y1: number;
    x2: number;
    y2: number;
    nodeStyle: NodeStyleInfo;
}

export const nodes = writable([] as FlowNode[]);
export const edges = writable([] as FlowEdge[]);

export function addNode(newNode: FlowNode) {
    nodes.update((oldNodeList) => {
        return [...oldNodeList, newNode];
    });
}

export function removeNode(id: string) {
    nodes.update((oldNodeList) => {
        return oldNodeList.filter((item) => item.id != id);
    });
}

export function updateNodeSize(id: string, width: number, height: number) {
    nodes.update((oldNodeList) => {
        const index = oldNodeList.findIndex((item) => item.id == id);
        if (index != -1) {
            oldNodeList[index].width = width;
            oldNodeList[index].height = height;
        }
        return [...oldNodeList];
    });
}

export function updateNodePosition(id: string, x: number, y: number) {
    nodes.update((oldNodeList) => {
        const index = oldNodeList.findIndex((item) => item.id == id);
        if (index != -1) {
            oldNodeList[index].position.x = x;
            oldNodeList[index].position.y = y;
        }
        return [...oldNodeList];
    });
}

export function initNodes() {
    const tmpNodeList: FlowNode[] = drawStore.nodeList.map((item) => ({
        id: item.node_id,
        type: getNodeType(item.content),
        position: {
            x: item.x,
            y: item.y,
        },
        width: item.w,
        height: item.h,
        data: item,
        selectable: !drawStore.readOnly && item.lock == false,
        draggable: !drawStore.readOnly && item.lock == false,
        zIndex: item.node_style.layer,
    }));
    nodes.update((oldNodeList) => {
        if (oldNodeList.length == 0) {
            return tmpNodeList;
        }
        const newNodeList: FlowNode[] = [];
        for (const newNode of tmpNodeList) {
            const newNodeData = newNode.data as ExDrawNodeInfo;
            const oldNode = oldNodeList.find((item) => item.id == newNode.id);
            if (oldNode != undefined) {
                oldNode.data = newNode.data;
                oldNode.position.x = newNodeData.x;
                oldNode.position.y = newNodeData.y;
                oldNode.width = newNodeData.w;
                oldNode.height = newNodeData.h;
                oldNode.selectable = newNode.selectable;
                oldNode.draggable = newNode.draggable;
                oldNode.zIndex = newNode.zIndex;
                newNodeList.push(oldNode);
            } else {
                newNodeList.push(newNode);
            }
        }
        return newNodeList;
    });
}

export async function removeEdges(edges: FlowEdge[]) {
    const tmpList = drawStore.edgeList.slice();
    const sessionId = await get_user_session();
    try {
        for (const edge of edges) {
            const edgeData = (edge.data as DrawEdgeInfo);
            if (drawStore.readOnly) {
                continue;
            }
            await request(remove_edge({
                session_id: sessionId,
                board_id: drawStore.boardInfo?.board_id ?? "",
                draw_id: drawStore.drawId,
                edge_key: edgeData.edge_key,
            }));
            drawStore.removeSelectEdgeKey(edgeData.edge_key);
        }
    } catch (e) {
        console.log(e);
        drawStore.edgeList = tmpList;
    }
}

export async function removeNodes(nodes: FlowNode[]) {
    const tmpList = drawStore.nodeList.slice();
    const sessionId = await get_user_session();
    try {
        for (const node of nodes) {
            if (drawStore.readOnly) {
                continue;
            }
            if ((node.data as ExDrawNodeInfo).lock) {
                continue;
            }
            await request(remove_node({
                session_id: sessionId,
                board_id: drawStore.boardInfo?.board_id ?? "",
                draw_id: drawStore.drawId,
                node_id: node.id,
            }));
            drawStore.removeSelectNodeId(node.id);
        }
    } catch (e) {
        console.log(e);
        drawStore.nodeList = tmpList;
    }
}

export async function moveNodes(nodes: FlowNode[]) {
    const tmpList = drawStore.nodeList.slice();
    const sessionId = await get_user_session();
    try {
        drawStore.skipUpdateNode = true;
        for (const node of nodes) {
            await request(
                update_node_position({
                    session_id: sessionId,
                    board_id: drawStore.boardInfo?.board_id ?? "",
                    draw_id: drawStore.drawId,
                    node_id: node.id,
                    x: node.position.x,
                    y: node.position.y,
                }));
        }
    } catch (e) {
        console.log(e);
        drawStore.nodeList = tmpList;
    } finally {
        drawStore.skipUpdateNode = false;
    }
    //更新节点
    for (const node of nodes) {
        await drawStore.onUpdateNode(node.id);
    }
}

export async function createDropNode(x: number, y: number, screenToFlowPosition: (clientPosition: XYPosition, options?: {
    snapToGrid: boolean;
}) => XYPosition) {
    const position = screenToFlowPosition({
        x: x,
        y: y,
    });


    if (
        typeof drawStore.curToolInfo == "object"
    ) {
        const sessionId = await get_user_session();
        const res = await request(
            create_node({
                session_id: sessionId,
                board_id: drawStore.boardInfo?.board_id ?? "",
                draw_id: drawStore.drawId,
                x: position.x,
                y: position.y,
                w: drawStore.curToolInfo.defaultWidth,
                h: drawStore.curToolInfo.defaultHeight,
                content: drawStore.curToolInfo.content,
                node_style: {
                    bg_color: "bg-surface-200",
                    border_width: "border-2",
                    border_color: "border-surface-300",
                    font_color: "text-surface-800",
                    layer: 0,
                },
            })
        );
        if (drawStore.curToolInfo.fromNodeId != undefined) {
            const fromNodeId = drawStore.curToolInfo.fromNodeId;
            const fromNode = drawStore.nodeList.find(item => item.node_id == fromNodeId);
            if (fromNode == undefined) {
                return;
            }

            let fromHandle = "";
            let toHandle = "";
            const xdiff = fromNode.x - position.x;
            const ydiff = fromNode.y - position.y;
            console.log("fromNode", fromNode.x, fromNode.y, "toNode", position.x, position.y)
            if (Math.abs(xdiff) > Math.abs(ydiff)) { //左右
                if (xdiff > 0) {
                    fromHandle = "l"
                    toHandle = "r";
                } else {
                    fromHandle = "r"
                    toHandle = "l";
                }
            } else {
                if (ydiff > 0) {
                    fromHandle = "t"
                    toHandle = "b";
                } else {
                    fromHandle = "b"
                    toHandle = "t";
                }
            }
            await request(create_edge({
                session_id: sessionId,
                board_id: drawStore.boardInfo?.board_id ?? "",
                draw_id: drawStore.drawId,
                edge_key: {
                    from_node_id: fromNodeId,
                    from_handle: fromHandle,
                    to_node_id: res.node_id,
                    to_handle: toHandle,
                },
                basic_info: {
                    edge_type: EDGE_TYPE_BEZIER,
                    stroke_width: 1,
                    color: "var(--color-secondary-900)",
                    has_start_arrow: false,
                    has_end_arrow: false,
                    label: "",
                    llm_link: false,
                },
            }));
        }
    }
    drawStore.curToolInfo = "move";
}


export function initEdges() {
    const tmpEdgeList: FlowEdge[] = drawStore.edgeList.map((item) => ({
        id: `${item.edge_key.from_node_id}-${item.edge_key.from_handle}-${item.edge_key.to_node_id}-${item.edge_key.to_handle}`,
        type: "DrawEdge",
        source: item.edge_key.from_node_id,
        target: item.edge_key.to_node_id,
        sourceHandle: item.edge_key.from_handle,
        targetHandle: item.edge_key.to_handle,
        data: item,
        selectable: drawStore.readOnly == false && item.basic_info.llm_link == false,
        markerStart: item.basic_info.has_start_arrow ? {
            type: MarkerType.ArrowClosed,
            width: 20,
            height: 20,
            color: item.basic_info.color,
        } : undefined,
        markerEnd: item.basic_info.has_end_arrow ? {
            type: MarkerType.ArrowClosed,
            width: 20,
            height: 20,
            color: item.basic_info.color,
        } : undefined,
        zIndex: 20,
    }));
    edges.set(tmpEdgeList);
}

async function createEdge(edgeKey: EdgeKey, basicInfo: BasicEdgeInfo) {
    const sessionId = await get_user_session();
    await request(create_edge({
        session_id: sessionId,
        board_id: drawStore.boardInfo?.board_id ?? "",
        draw_id: drawStore.drawId,
        edge_key: edgeKey,
        basic_info: basicInfo,
    }));
}

export function onCreateEdge(conn: Connection) {
    if (!(drawStore.myMember?.admin == true)) {
        return;
    }
    if (conn.source == conn.target) {
        return;
    }
    //llm节点不能作为起始节点
    const sourceNode = drawStore.nodeList.find(item => item.node_id == conn.source);
    if (sourceNode == undefined || sourceNode.content.LlmAnswerContent != undefined || sourceNode.content.LlmAskContent != undefined) {
        return;
    }
    //llm答案和起始节点不能作为终点
    const targetNode = drawStore.nodeList.find(item => item.node_id == conn.target);
    if (targetNode == undefined || targetNode.content.LlmAnswerContent != undefined) {
        return;
    }
    const item: DrawEdgeInfo = {
        edge_key: {
            from_node_id: conn.source,
            from_handle: conn.sourceHandle ?? "",
            to_node_id: conn.target,
            to_handle: conn.targetHandle ?? "",
        },
        basic_info: {
            edge_type: EDGE_TYPE_BEZIER,
            stroke_width: 1,
            color: "var(--color-secondary-900)",
            has_start_arrow: false,
            has_end_arrow: false,
            label: "",
            llm_link: false,
        },
        create_time: dayjs().valueOf(),
        update_time: dayjs().valueOf(),
    };
    createEdge(item.edge_key, item.basic_info);
    const newEdge: FlowEdge = {
        id: `${item.edge_key.from_node_id}-${item.edge_key.from_handle}-${item.edge_key.to_node_id}-${item.edge_key.to_handle}`,
        type: "DrawEdge",
        source: item.edge_key.from_node_id,
        target: item.edge_key.to_node_id,
        sourceHandle: item.edge_key.from_handle,
        targetHandle: item.edge_key.to_handle,
        data: item,
    };
    return newEdge;
}

export function unSelectNode(nodeId: string) {
    nodes.update((oldNodeList) => {
        const newNodeList = oldNodeList.slice();
        const index = newNodeList.findIndex(item => item.id == nodeId);
        if (index != -1) {
            newNodeList[index].selected = false;
        }
        return newNodeList;
    });
}

let lastSendTime = 0;
let lastPostion = { x: 0, y: 0 }
export async function sendMyMousePositon(x: number, y: number, screenToFlowPosition: (clientPosition: XYPosition, options?: {
    snapToGrid: boolean;
}) => XYPosition) {
    const nowTime = dayjs().valueOf();
    if (nowTime - lastSendTime < 500) {
        return;
    }
    const curPosition = screenToFlowPosition({ x, y });
    if (Math.abs(lastPostion.x - curPosition.x) < 20 && Math.abs(lastPostion.y - curPosition.y) < 20) {
        return;
    }
    lastPostion = curPosition;
    const sessionId = await get_user_session();
    await request(report_mouse_position({
        session_id: sessionId,
        board_id: drawStore.boardInfo?.board_id ?? "",
        draw_id: drawStore.drawId,
        x: curPosition.x,
        y: curPosition.y,
    }));
}